/*
 *  Copyright (c) 2019-2020, 冷冷 (wangiegie@gmail.com).
 *  <p>
 *  Licensed under the GNU Lesser General Public License 3.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  <p>
 * https://www.gnu.org/licenses/lgpl.html
 *  <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.lanswon.icc.gateway.filter;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.http.HttpUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lanswon.icc.common.core.constant.MsgTemplate;
import com.lanswon.icc.common.core.constant.ResultConstant;
import com.lanswon.icc.common.core.constant.SecurityConstant;
import com.lanswon.icc.common.core.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * @date 2019/2/1
 * 密码解密工具类
 */
@Slf4j
@Component
public class PasswordDecoderFilter extends AbstractGatewayFilterFactory {
    @Autowired
    ObjectMapper objectMapper;
    private static final String PASSWORD = "password";
    private static final String KEY_ALGORITHM = "AES";
    @Value("${security.encode.key}")
    private String encodeKey;
//    @Autowired
//     LogService logService;


    private static String decryptAES(String data, String pass) {
        AES aes = new AES(Mode.CBC, Padding.NoPadding,
                new SecretKeySpec(pass.getBytes(), KEY_ALGORITHM),
                new IvParameterSpec(pass.getBytes()));
        byte[] result = aes.decrypt(Base64.decode(data.getBytes(StandardCharsets.UTF_8)));
        return new String(result, StandardCharsets.UTF_8);
    }

    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();

            // 不是登录请求，直接向下执行
            if (!StrUtil.containsAnyIgnoreCase(request.getURI().getPath(), SecurityConstant.OAUTH_TOKEN_URL)) {
                return chain.filter(exchange);
            }

            URI uri = exchange.getRequest().getURI();
            String queryParam = uri.getRawQuery();
            Map<String, String> paramMap = HttpUtil.decodeParamMap(queryParam, CharsetUtil.UTF_8);

            String password = paramMap.get(PASSWORD);
            if (StrUtil.isNotBlank(password)) {
                try {
                    password = decryptAES(password, encodeKey);
                } catch (Exception e) {

                    log.error("密码解密失败:{}", password);
                    ServerHttpResponse response = exchange.getResponse();
                    response.setStatusCode(HttpStatus.OK);
                    HttpHeaders headers = response.getHeaders();
                    headers.setContentType(MediaType.APPLICATION_JSON_UTF8);

//                    logService.saveGateWayErrorLog(MsgTemplate.ERROR_USER_OR_PWD);

                    try {
                        return response.writeWith(Mono.just(response.bufferFactory()
                                .wrap(objectMapper.writeValueAsBytes(
                                        new Result(ResultConstant.EX_DATA_IS_NULL,MsgTemplate.ERROR_USER_OR_PWD)
                                ))));
                    } catch (JsonProcessingException e1) {
                        log.error("对象输出异常", e1);
                        e1.printStackTrace();
                    }


                }
                paramMap.put(PASSWORD, password.trim());
            }

            URI newUri = UriComponentsBuilder.fromUri(uri)
                    .replaceQuery(HttpUtil.toParams(paramMap))
                    .build(true)
                    .toUri();

            ServerHttpRequest newRequest = exchange.getRequest().mutate().uri(newUri).build();
            return chain.filter(exchange.mutate().request(newRequest).build());
        };
    }


    /**
     * AES加密
     * @param args
     */
    public static void main(String[] args) throws Exception {



        String pass = "(*^_^*)++(*^_^*)";
        String data ="Gp/nb0DaNa3g7LMBor6avA==";

        System.out.println(pass.length());



        AES aes = new AES(Mode.CBC, Padding.NoPadding,
                new SecretKeySpec(pass.getBytes(), KEY_ALGORITHM),
                new IvParameterSpec(pass.getBytes()));

        byte[] bytes = data.getBytes(StandardCharsets.UTF_8);

        byte[] decode = Base64.decode(bytes);


        byte[] result = aes.decrypt(decode);
        String str =  new String(result, StandardCharsets.UTF_8);

        System.out.println("解密后："+str);




        String s = decryptAES(data, "(*^_^*)++(*^_^*)");
        System.out.println(s);




                 s = decryptAES("LFEt60GoMTj5/mQQ7HjJeA==", "thanks,pig4cloud");
        System.out.println(s);


    }

    @Test
    public void test() throws UnsupportedEncodingException {
        String pass = "(*^_^*)++(*^_^*)";
        String data = "123456";

//        AES aes = new AES(Mode.CBC, Padding.NoPadding,
//                new SecretKeySpec(pass.getBytes(), KEY_ALGORITHM),
//                new IvParameterSpec(pass.getBytes()));
//
//        byte[] encrypt = aes.encrypt(data.getBytes("UTF-8"));
//
//        String encode = Base64.encode(encrypt);

        AES aes = new AES(Mode.CBC, Padding.NoPadding,
                new SecretKeySpec(pass.getBytes(), KEY_ALGORITHM),
                new IvParameterSpec(pass.getBytes()));
        byte[] result = aes.encrypt(Base64.encode(data.getBytes(StandardCharsets.UTF_8)));


        System.out.println(new String(result, StandardCharsets.UTF_8) );

    }
}
